package dht;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Objects;

public class HostAddress {
    
    private static final byte STRING_TERMINATOR = 0;
    
    private final InetAddress address;
    public InetAddress address() {
        return address;
    }
    
    private final String host;
    public String hostName() {
        return host;
    }
    
    private final int port;
    public int port() {
        return port;
    }
    
    private byte[] bytes;
    public byte[] getBytes() {
        if (bytes == null) {
            byte[] name = host.getBytes();
            bytes = ByteBuffer.allocate(name.length + 1 + 4)
                    .put(name, 0, name.length)
                    .put((byte)0)
                    .putInt(port)
                    .array();
        }
        
        return bytes;
    }
    
    public HostAddress(String host, int port) throws UnknownHostException {
        this(Inet4Address.getByName(host), port);
    }
    
    public HostAddress (InetAddress addr, int port) {
        this.host = addr.getHostName();
        this.address = addr;
        this.port = port;
    }

    public int hashCode() {
        int hash = 3;
        hash = 89 * hash + Objects.hashCode(this.address);
        hash = 89 * hash + this.port;
        return hash;
    }
    
    public boolean equals(Object other) {
        if (!(other instanceof HostAddress))
            return false;
        HostAddress otherAddr = (HostAddress)other;
        return address.equals(otherAddr.address)
            && port == otherAddr.port;  
    }
    
    public static HostAddress fromBytes(byte[] bytes) 
    throws UnknownHostException {
        return fromBytes(bytes, 0);
    }
    
    public static HostAddress fromBytes(byte[] bytes, int offset) 
    throws UnknownHostException {
        /*
         * note: this doesn't only wrap the array from offset - length,
         * it wraps the entire array and sets the starting position at
         * the offset.
         */
        ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, bytes.length - offset);
        
        String hostName = getHostName(buffer);
        int port = buffer.getInt();
        
        return new HostAddress(hostName, port);
    }
     
    private static String getHostName(ByteBuffer buffer) 
    throws UnknownHostException {
        // the name is the length of the array minus the OpCode and proposal num
        // (6 bytes) and the port number (4 bytes)
        byte[] name = new byte[buffer.array().length - (6 + 4)];
        buffer.get(name, 0, name.length);
        return new String(name);
    }
    
}
